﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace SceneManager
{
    public class ComplexModel : DrawableObject
    {
        public Quaternion Rotation { get; set; } // Quaternion?
        public Vector3 Scale { get; set; }

        public Vector2 TextureScale { get; set; } // TODO: take care of it

        public List<SimpleObject> CollisionMask { get; set; }

        public Model Model { get; protected set; }
        protected Material[] ModelMaterials;

        public ComplexModel(Game game, string assetName, Vector3 position, Vector3 rotation, Vector3 scale, Material material) : this(game, game.Content.Load<Model>(assetName), position, rotation, scale, material)
        {
        }
        public ComplexModel(Game game, Model model, Vector3 position, Vector3 rotation, Vector3 scale, Material material) : base(game)
        {
            Model = model;
            ModelMaterials = new Material[Model.Meshes.Sum(m => m.MeshParts.Count)];

            for (int i = 0; i < ModelMaterials.Length; i++)
                ModelMaterials[i] = material;

            Position = position;
            //Rotation = rotation;
            Rotation = Quaternion.Identity;
            Scale = scale;
        }
        public ComplexModel(Game game, string assetName, Vector3 position, Vector3 rotation, Vector3 scale) : this(game, game.Content.Load<Model>(assetName), position, rotation, scale)
        {
        }
        public ComplexModel(Game game, Model model, Vector3 position, Vector3 rotation, Vector3 scale) : base(game)
        {
            Model = model;
            ModelMaterials = new Material[Model.Meshes.Sum(m => m.MeshParts.Count)];

            int i = 0;
            foreach (ModelMesh mesh in Model.Meshes)
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    Texture2D texture;
                    float specularIntensity;
                    float specularPower;

                    if (meshPart.Effect is BasicEffect)
                    {
                        texture = (meshPart.Effect as BasicEffect).Texture;
                        specularIntensity = 0; // FIXME
                        specularPower = (meshPart.Effect as BasicEffect).SpecularPower;
                    }
                    else
                    {
                        texture = meshPart.Effect.Parameters["Texture"].GetValueTexture2D();
                        specularIntensity = 0;
                        specularPower = meshPart.Effect.Parameters["SpecularPower"].GetValueSingle();
                    }

                    ModelMaterials[i] = new Material(texture, specularIntensity, specularPower);

                    i++;
                }

            Position = position;
            //Rotation = rotation;
            Rotation = Quaternion.Identity;
            Scale = scale;
        }

        public override void Draw(Camera camera, GameTime gameTime)
        {
            Matrix modelWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromQuaternion(Rotation) * /*Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) */ Matrix.CreateTranslation(Position);

            Matrix[] transforms = new Matrix[Model.Bones.Count];
            Model.CopyAbsoluteBoneTransformsTo(transforms);

            int i = 0;
            foreach (ModelMesh mesh in Model.Meshes)
            {
                Matrix meshWorld = transforms[mesh.ParentBone.Index] * modelWorld;

                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    meshPart.Effect = Effect;

                    meshPart.Effect.Parameters["World"].SetValue(meshWorld);
                    meshPart.Effect.Parameters["View"].SetValue(camera.View);
                    meshPart.Effect.Parameters["Projection"].SetValue(camera.Projection);
                    meshPart.Effect.Parameters["Texture"].SetValue(ModelMaterials[i].Texture);
                    
                    if (meshPart.Effect.Parameters.Count(p => p.Name == "SpecularIntensity") == 1)
                        meshPart.Effect.Parameters["SpecularIntensity"].SetValue(ModelMaterials[i].SpecularIntensity);
                    if (meshPart.Effect.Parameters.Count(p => p.Name == "SpecularPower") == 1)
                        meshPart.Effect.Parameters["SpecularPower"].SetValue(ModelMaterials[i].SpecularPower);

                    i++;
                }

                mesh.Draw();
            }
        }
    }
}
